# Copyright (c) 2025 Li Auto Inc. and its affiliates
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 3.16)
project(livbs)

# 清空CMAKE_CXX_FLAGS
set(CMAKE_CXX_FLAGS "")
set(CMAKE_C_FLAGS "")
set(UNIFIED_INCLUDE_DIRS_PRIVATE "")
set(UNIFIED_LINK_LIBS "")
set(UNIFIED_DEFINES "")
set(UNIFIED_DEFINES_PRIVATE "")
set(UNIFIED_SOURCES "")
set(CMAKE_INSTALL_MESSAGE NEVER)

# 添加统一库编译选项
option(BUILD_UNIFIED_LIB "Build unified library (livbs) instead of multiple libraries" ON)
message(STATUS "BUILD_UNIFIED_LIB is set to: ${BUILD_UNIFIED_LIB}")

# Using ccache by default
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)

set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "")

# 设置依赖库路径
set(ECDR_INCLUDE_PATH ${CMAKE_BINARY_DIR}/thirdparty/ECDR/include)
set(ECDR_LIB_PATH ${CMAKE_INSTALL_PREFIX}/lib)
set(THIRDPARTY_PATH ${CMAKE_SOURCE_DIR}/thirdparty)
set(UTILS_PATH ${CMAKE_SOURCE_DIR}/utils)

set(ENABLE_TRACER OFF)
set(CONAN_INSTALL ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(CMAKE_CXX_FLAGS_RELEASE "-O3")
    set(CMAKE_C_FLAGS_RELEASE "-O3")
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(CMAKE_CXX_FLAGS_DEBUG "-g -O3")
    set(CMAKE_C_FLAGS_DEBUG "-g -O3")
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC -Wall -Wno-reorder")
    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fPIC -Wall -Wno-reorder")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--strip-all -z nonexecstack -z relro -z now")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--strip-all -z nonexecstack -z relro -z now")
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC -Wall -Wno-reorder")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fPIC -Wall -Wno-reorder")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -z nonexecstack -z relro -z now")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -z nonexecstack -z relro -z now")
endif()

# 设置全局变量，用于收集所有源文件和包含路径
set(UNIFIED_SOURCES "" CACHE INTERNAL "Unified sources for all libraries")
set(UNIFIED_INCLUDE_DIRS "" CACHE INTERNAL "Unified include directories for all libraries")
set(UNIFIED_LINK_LIBS "" CACHE INTERNAL "Unified link libraries for all libraries")
set(UNIFIED_DEFINES "" CACHE INTERNAL "Unified defines for all libraries")
set(UNIFIED_DEFINES_PRIVATE "" CACHE INTERNAL "Unified defines for all libraries")

###############################################################################
# Options
###############################################################################
option(BUILD_SHARED_LIBS "Create shared libraries by default" ON)
option(SECURITY "Activate security" OFF)
option(SECURITY "Activate security" OFF)
option(BUILD_DSF "Activate liddsdsf" OFF)
option(EXAMPLE ON)

set(TLS_FOUND 0)
if(SECURITY OR TLS_FOUND)
    find_package(OpenSSL REQUIRED)
    set(HAVE_SECURITY 1)
    if(NOT CONAN_BUILD)
        option(VBSAUTH "Activate VBSAuth" ON)
    endif()
    set(LINK_SSL 1)
else()
    find_package(OpenSSL)
    set(HAVE_SECURITY 0)
    set(LINK_SSL 0)
endif()

option(SQLITE3_SUPPORT "Activate SQLITE3 support" ON)
set(SQLITE3_SUPPORT ON)
if(SQLITE3_SUPPORT)
    message(STATUS "SQLite3 support is enabled.")
    set(HAVE_SQLITE3 1)
    enable_language(C)
else()
    message(STATUS "SQLite3 support is disabled.")
    set(HAVE_SQLITE3 0)
endif()

option(COMPILE_COVB "Test coverage option" OFF)
message("COMPILE_COVB Value is: ${COMPILE_COVB}")

if(COMPILE_COVB)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprofile-arcs -ftest-coverage")
endif()

# Option to enable strict real-time. In this case, several API functions have a real-time behaviour.
# * Publisher::write() - Uses ReliabilityQosPolicy.max_blocking_time
# * Subscriber::takeNextData() - Uses ReliabilityQosPolicy.max_blocking_time
# * Subscriber::readNextData() - Uses ReliabilityQosPolicy.max_blocking_time
option(STRICT_REALTIME "Enable a strict real-time behavour." OFF)
if(STRICT_REALTIME)
    set(HAVE_STRICT_REALTIME 1)
else()
    set(HAVE_STRICT_REALTIME 0)
endif()

# 添加缓存变量控制是否重新下载依赖
option(FORCE_DOWNLOAD_DEPENDENCIES "Force download dependencies even if they exist" OFF)

list(APPEND UNIFIED_INCLUDE_DIRS
    ${CMAKE_BINARY_DIR}
    ${CMAKE_BINARY_DIR}/evbs/include
    ${CMAKE_BINARY_DIR}/rpc/include
    ${CMAKE_BINARY_DIR}/erpc/include
    ${CMAKE_BINARY_DIR}/framework/vui/include
    ${CMAKE_BINARY_DIR}/dsf/include
    ${CMAKE_BINARY_DIR}/utils/include
)

list(APPEND UNIFIED_INCLUDE_DIRS
    ${PROJECT_SOURCE_DIR}/rpc/include
)

# 添加Asio依赖
include(FetchContent)

# 设置Asio依赖下载和构建路径
set(ASIO_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty_other/asio/src")
set(ASIO_BINARY_DIR "${CMAKE_BINARY_DIR}/thirdparty_other/asio/build")

if(NOT EXISTS "${ASIO_SOURCE_DIR}" OR NOT EXISTS "${ASIO_BINARY_DIR}" OR FORCE_DOWNLOAD_DEPENDENCIES)
    FetchContent_Declare(
        asio
        GIT_REPOSITORY https://github.com/chriskohlhoff/asio.git
        GIT_TAG asio-1-29-0
        SOURCE_DIR ${ASIO_SOURCE_DIR}
        BINARY_DIR ${ASIO_BINARY_DIR}
    )
    message(STATUS "正在下载Asio依赖（可能需要几分钟，请耐心等待）...")
    FetchContent_MakeAvailable(asio)
endif()

# 添加Asio的包含路径
list(APPEND UNIFIED_INCLUDE_DIRS
    ${ASIO_SOURCE_DIR}/asio/include
)

# 添加foonathan_memory依赖
# 设置依赖下载和构建路径
set(FOONATHAN_MEMORY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty_other/foonathan_memory/src")
set(FOONATHAN_MEMORY_BINARY_DIR "${CMAKE_BINARY_DIR}/thirdparty_other/foonathan_memory/build")

if(NOT EXISTS "${FOONATHAN_MEMORY_SOURCE_DIR}" OR NOT EXISTS "${FOONATHAN_MEMORY_BINARY_DIR}" OR FORCE_DOWNLOAD_DEPENDENCIES)
    FetchContent_Declare(
        foonathan_memory
        GIT_REPOSITORY https://github.com/foonathan/memory.git
        GIT_TAG v0.7-1
        SOURCE_DIR ${FOONATHAN_MEMORY_SOURCE_DIR}
        BINARY_DIR ${FOONATHAN_MEMORY_BINARY_DIR}
    )
    message(STATUS "正在下载foonathan_memory依赖（可能需要几分钟，请耐心等待）...")
    FetchContent_MakeAvailable(foonathan_memory)
endif()

# 添加foonathan_memory的包含路径
list(APPEND UNIFIED_INCLUDE_DIRS
    ${FOONATHAN_MEMORY_SOURCE_DIR}/include
    ${FOONATHAN_MEMORY_BINARY_DIR}/src
)

# 添加TinyXML2依赖
set(TINYXML2_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty_other/tinyxml2/src")
set(TINYXML2_BINARY_DIR "${CMAKE_BINARY_DIR}/thirdparty_other/tinyxml2/build")

if(NOT EXISTS "${TINYXML2_SOURCE_DIR}" OR NOT EXISTS "${TINYXML2_BINARY_DIR}" OR FORCE_DOWNLOAD_DEPENDENCIES)
    FetchContent_Declare(
        tinyxml2
        GIT_REPOSITORY https://github.com/leethomason/tinyxml2.git
        GIT_TAG 10.0.0
        SOURCE_DIR ${TINYXML2_SOURCE_DIR}
        BINARY_DIR ${TINYXML2_BINARY_DIR}
    )
    message(STATUS "正在下载TinyXML2依赖（可能需要几分钟，请耐心等待）...")
    FetchContent_MakeAvailable(tinyxml2)
endif()

# 添加TinyXML2的包含路径
list(APPEND UNIFIED_INCLUDE_DIRS
    ${TINYXML2_SOURCE_DIR}
)

# 设置TinyXML2的库路径
set(TINYXML2_LIBRARY tinyxml2)
set(TINYXML2_INCLUDE_DIR ${TINYXML2_SOURCE_DIR})

# 添加C++17标准到UNIFIED_DEFINES
set(UNIFIED_DEFINES "${UNIFIED_DEFINES}" CACHE INTERNAL "Unified defines for all libraries" FORCE)
set(UNIFIED_DEFINES_PRIVATE "${UNIFIED_DEFINES_PRIVATE}" CACHE INTERNAL "Unified defines for all libraries" FORCE)
set(UNIFIED_SOURCES "${UNIFIED_SOURCES}" CACHE INTERNAL "Unified sources for all libraries" FORCE)
set(UNIFIED_INCLUDE_DIRS "${UNIFIED_INCLUDE_DIRS}" CACHE INTERNAL "Unified include directories for all libraries" FORCE)
set(UNIFIED_INCLUDE_DIRS_PRIVATE "${UNIFIED_INCLUDE_DIRS_PRIVATE}" CACHE INTERNAL "Unified include directories for all libraries" FORCE)
set(UNIFIED_LINK_LIBS "${UNIFIED_LINK_LIBS}" CACHE INTERNAL "Unified link libraries for all libraries" FORCE)

# 在统一库模式下，子目录只收集源文件和配置信息
add_subdirectory(utils)
add_subdirectory(thirdparty)
add_subdirectory(evbs)
add_subdirectory(rpc)
add_subdirectory(dsf)
add_subdirectory(framework)
add_subdirectory(tools/daemon)
if(VBSAUTH)
    add_subdirectory(vbsauth)
endif()
# Test Cases
add_subdirectory(examples)

add_definitions(${UNIFIED_DEFINES})

# 创建统一库 NDK保持动态库
if (NOT BUILD_SHARED_LIBS)
    add_library(livbs STATIC ${UNIFIED_SOURCES})
else()
    add_library(livbs SHARED ${UNIFIED_SOURCES})
endif()

# 设置包含目录
target_include_directories(livbs PUBLIC ${UNIFIED_INCLUDE_DIRS})
target_include_directories(livbs PRIVATE ${UNIFIED_INCLUDE_DIRS_PRIVATE})

# 设置链接库
list(APPEND UNIFIED_LINK_LIBS
    rt
    pthread
    stdc++
)

list(APPEND UNIFIED_LINK_LIBS
    ecdr
    tinyxml2
)

target_link_directories(livbs
    PUBLIC
    ${ECDR_LIB_PATH}
    ${TINYXML_LIB_PATH}
    ${GTEST_LIB_PATH}
    $ENV{ROOT_PATH}/lib
    ${CMAKE_BINARY_DIR}/lib
    )

target_link_libraries(livbs PUBLIC ${UNIFIED_LINK_LIBS})

# Installation paths
set(TOOL_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/tool/ CACHE PATH "Installation directory for tool")

# 安装统一库
install(TARGETS livbs
    LIBRARY DESTINATION ${LIB_INSTALL_DIR}
    ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
    RUNTIME DESTINATION ${BIN_INSTALL_DIR}
    COMPONENT libraries
)

# 安装头文件
install(DIRECTORY
    ${CMAKE_CURRENT_SOURCE_DIR}/utils/include/
    ${CMAKE_CURRENT_SOURCE_DIR}/evbs/include/
    ${CMAKE_CURRENT_SOURCE_DIR}/rpc/include/
    ${CMAKE_CURRENT_SOURCE_DIR}/framework/vui/include/
    ${CMAKE_CURRENT_SOURCE_DIR}/dsf/include/
    DESTINATION ${INCLUDE_INSTALL_DIR}
    COMPONENT headers
    FILES_MATCHING
    PATTERN "*.h"
    PATTERN "*.hpp"
    PATTERN "*.ipp"
)

install(DIRECTORY
    ${CMAKE_BINARY_DIR}/utils/include/
    DESTINATION ${INCLUDE_INSTALL_DIR}
    COMPONENT headers
)
